package com.jrx.anytxn.investor.service.impl;

import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.function.UncheckedFunction;
import com.jrx.anytxn.common.uitl.BeanUtils;
import com.jrx.anytxn.common.uitl.CollectorsUtils;
import com.jrx.anytxn.investor.bean.InvestorCastAccountTransactionBean;
import com.jrx.anytxn.investor.bean.InvestorPaymentSaveBean;
import com.jrx.anytxn.investor.entity.AmLoanAccountInvestorInfo;
import com.jrx.anytxn.investor.entity.AmLoanMainInvestorInfo;
import com.jrx.anytxn.investor.entity.AmRepaymentPlanInvestorInfo;
import com.jrx.anytxn.investor.service.IInvestorAccountService;
import com.jrx.anytxn.investor.service.IInvestorFeeService;
import com.jrx.anytxn.param.dto.investor.PrInvestorPrepaymentFeeRes;
import com.jrx.anytxn.param.dto.investor.PrInvestorPreterminationFeeRes;
import com.jrx.anytxn.param.entity.PrInvestorPrepaymentFee;
import com.jrx.anytxn.param.entity.PrInvestorPreterminationFee;
import com.jrx.anytxn.param.service.investor.IPrInvestorPrepaymentFeeService;
import com.jrx.anytxn.param.service.investor.IPrInvestorPreterminationFeeService;
import com.jrx.anytxn.transaction.bean.DelqParamBean;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @program: anytxn-cf-transaction
 * @description:
 * @author: xiaoyu.jing
 * @date: 2020-05-26 14:02
 **/
@Service
public class InvestorFeeServiceImpl implements IInvestorFeeService {

    private static final Logger logger = LoggerFactory.getLogger(InvestorFeeServiceImpl.class);

    @Autowired
    private IPrInvestorPreterminationFeeService preterminationFeeService;
    @Autowired
    private IInvestorAccountService accountService;
    @Autowired
    private IPrInvestorPrepaymentFeeService prepaymentFeeService;


    /**
     * 计算提前结清手续费,获取提前结清费用交易账户,分期费用交易账户，利息交易账户
     * @param saveBean
     * @param loanMainInvestorInfo
     * @param loanAccountInvestorInfo
     * @param delqParamBean
     * @param bussinessDate
     * @throws TxnException
     */
    @Override
    public void castPayOffFeeAndIntrAcct(InvestorPaymentSaveBean saveBean, AmLoanMainInvestorInfo loanMainInvestorInfo,
                                         AmLoanAccountInvestorInfo loanAccountInvestorInfo, List<AmRepaymentPlanInvestorInfo> planList, DelqParamBean delqParamBean, Date bussinessDate) throws TxnException {
        logger.info("计算提前结清手续费,获取交易账户,loanMainInvestorInfo:{}", BeanUtils.toMap(loanMainInvestorInfo));

        //获取提前结清费用参数
        PrInvestorPreterminationFee res = preterminationFeeService.findByPreterminationFeeId(loanMainInvestorInfo.getInvestorPayoffTableId(),loanMainInvestorInfo.getTenantId());
        logger.info("提前结清费用参数,PrPreterminationFeeTableRes:{}", BeanUtils.toMap(res));

        if(null != res.getWaiveFeeTenor() && res.getWaiveFeeTenor() <= loanAccountInvestorInfo.getPayedTenor()){
            return;
        }

        //未抛帐的还款计划
        //筛选未抛帐
        List<AmRepaymentPlanInvestorInfo> planInfoList = planList.stream()
                .filter(amRepaymentPlanInfo -> TransBizConstant.LOAN_PLAN_STATUS_0.equals(amRepaymentPlanInfo.getPlanStatus()))//获取还款计划
                .collect(Collectors.toList());

        String liabilityFlag = planList.stream().findFirst().get().getLiabilityFlag();

        //生成提前结清费用交易账户
        BigDecimal remainPrincipal = loanAccountInvestorInfo.getRemainPrincipal();
        BigDecimal payOffFee = this.calculationPayOffFee(res,remainPrincipal);
        if (payOffFee.compareTo(BigDecimal.ZERO) > 0) {
            //如果提前结清手续费大于0，则生成相应的费用交易账户
            InvestorCastAccountTransactionBean castPaymentFeeAccount = accountService.castPaymentFeeAccount(loanMainInvestorInfo,loanAccountInvestorInfo,
                    TransBizConstant.TXN_CODE_INST_PAYOFF_FEE, payOffFee, bussinessDate,liabilityFlag);
            saveBean.addSaveAcct(castPaymentFeeAccount.getAmAccountMainInfo());
            saveBean.addAcctGroupByTypeMap(castPaymentFeeAccount.getAmAccountMainInfo());
            saveBean.addSaveGlList(castPaymentFeeAccount.getTlGlInterfaceInfoList());
            logger.info("提前结清费用交易账户,castPaymentFeeAccount:{}", BeanUtils.toMap(castPaymentFeeAccount));
        }

        //获取分期费用账户
        List<InvestorCastAccountTransactionBean> castInstallmentFeeAcctList = this.castInstallmentFeeAcct(res, loanMainInvestorInfo,
                loanAccountInvestorInfo, planInfoList, bussinessDate);
        castInstallmentFeeAcctList.forEach(castAccountTransactionBean -> {
            saveBean.addSaveAcct(castAccountTransactionBean.getAmAccountMainInfo());
            saveBean.addAcctGroupByTypeMap(castAccountTransactionBean.getAmAccountMainInfo());
            saveBean.addSaveGlList(castAccountTransactionBean.getTlGlInterfaceInfoList());
        });


        //获取未抛期数利息交易账户
        List<InvestorCastAccountTransactionBean> castAccountTransactionBeanList = this.castIntrAcct(res, loanMainInvestorInfo, loanAccountInvestorInfo,
                planInfoList, delqParamBean,bussinessDate);
        castAccountTransactionBeanList.forEach(castAccountTransactionBean -> {
            saveBean.addSaveAcct(castAccountTransactionBean.getAmAccountMainInfo());
            saveBean.addAcctGroupByTypeMap(castAccountTransactionBean.getAmAccountMainInfo());
            saveBean.addSaveGlList(castAccountTransactionBean.getTlGlInterfaceInfoList());
        });
    }

    /**
     * 计算提前结清罚费
     *
     * @param res
     * @param remainPrincipal
     * @return
     */
    private BigDecimal calculationPayOffFee(PrInvestorPreterminationFee res, BigDecimal remainPrincipal) {
        BigDecimal feeAmt = BigDecimal.ZERO;
        if (TransBizConstant.ADVANCE_SETTLE_FEE_CHARGE_OPTION_0.equals(res.getFeeChargeOption())) {
            //按比例
            feeAmt = remainPrincipal.multiply(res.getFeeChargePercent()).setScale(TransBizConstant.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP);
        } else if (TransBizConstant.ADVANCE_SETTLE_FEE_CHARGE_OPTION_1.equals(res.getFeeChargeOption())) {
            //按固定金额
            feeAmt = res.getFeeChargeAmount();
        }

        //比较最大金额
        if (null !=res.getMaxAmount() && feeAmt.compareTo(res.getMaxAmount()) > 0) {
            feeAmt = res.getMaxAmount();
        }

        //比较最小金额
        if (null !=res.getMinAmount() && feeAmt.compareTo(res.getMinAmount()) < 0) {
            feeAmt = res.getMinAmount();
        }
        return feeAmt;
    }

    /**
     * 通过订单，还款计划抛出分期费用交易账户
     *
     * @param res
     * @param loanMainInfo
     * @param planInfoList
     * @param bussinessDate
     * @return
     */
    private List<InvestorCastAccountTransactionBean> castInstallmentFeeAcct(PrInvestorPreterminationFee res, AmLoanMainInvestorInfo loanMainInfo,
                                                                    AmLoanAccountInvestorInfo amLoanAccountInfo,
                                                                    List<AmRepaymentPlanInvestorInfo> planInfoList, Date bussinessDate) {
        List<InvestorCastAccountTransactionBean> castAccountTransactionBeanList = new ArrayList<>();
        String feeMethod = res.getFeeMethod();//费用收取方式
        if (StringUtils.isNotBlank(feeMethod)) {
            UncheckedFunction<AmRepaymentPlanInvestorInfo, InvestorCastAccountTransactionBean> getInstallmentFee = plan -> {
                //生成费用交易账户
                InvestorCastAccountTransactionBean castInstallmentFeeAccount = accountService.castInstallmentFeeAccount(loanMainInfo,
                        amLoanAccountInfo, plan, bussinessDate);
                logger.info("分期费用交易账户 castInstallmentFeeAccount:{}", BeanUtils.toMap(castInstallmentFeeAccount));
                return castInstallmentFeeAccount;
            };

            if (TransBizConstant.ADVANCE_SETTLE_FEE_METHOD_1.equals(feeMethod)) {//剩余期数都收费
                logger.info("所有剩余期数抛出费用交易账户");
                castAccountTransactionBeanList = planInfoList.stream()
                        .map(CollectorsUtils.tranToUncheck(getInstallmentFee)) //生成交易账户
                        .filter(Objects::nonNull)//筛选生成交易账户不为空
                        .collect(Collectors.toList());
                return castAccountTransactionBeanList;
            } else if (TransBizConstant.ADVANCE_SETTLE_FEE_METHOD_2.equals(feeMethod)) {//剩余X期收费
                int feeTenor = res.getFeeTenor();//收取费用期数
                logger.info("剩余{}期抛出费用交易账户", feeTenor);
                castAccountTransactionBeanList = planInfoList.stream()
                        .filter(plan -> plan.getBillingTenor() <= feeTenor + amLoanAccountInfo.getCastTenor())//筛选符合期数范围
                        .map(CollectorsUtils.tranToUncheck(getInstallmentFee))  //生成交易账户
                        .filter(Objects::nonNull)//筛选生成交易账户不为空
                        .collect(Collectors.toList());
            }
        }
        return castAccountTransactionBeanList;
    }

    /**
     * 通过订单，还款计划抛出利息交易账户
     *
     * @param res
     * @param loanMainInfo
     * @param planInfoList
     * @param bussinessDate
     * @return
     */
    private List<InvestorCastAccountTransactionBean> castIntrAcct(PrInvestorPreterminationFee res, AmLoanMainInvestorInfo loanMainInfo,
                                                          AmLoanAccountInvestorInfo loanAccountInfo, List<AmRepaymentPlanInvestorInfo> planInfoList,
                                                          DelqParamBean delqParamBean, Date bussinessDate) {
        List<InvestorCastAccountTransactionBean> castAccountTransactionBeans = new ArrayList<>();
        String intMethod = res.getIntMethod();
        if (StringUtils.isNotBlank(intMethod)) {//利息收取方式
            UncheckedFunction<AmRepaymentPlanInvestorInfo, InvestorCastAccountTransactionBean> getIntrAcct = plan -> {
                //生成利息交易账户
                InvestorCastAccountTransactionBean castIntrAccount = accountService.castIntrAccount(loanMainInfo, loanAccountInfo,plan,
                        delqParamBean,bussinessDate);//生成利息交易账户
                logger.info("利息交易账户 castIntrAccount:{}", BeanUtils.toMap(castIntrAccount));
                return castIntrAccount;
            };

            if (TransBizConstant.ADVANCE_SETTLE_FEE_METHOD_1.equals(intMethod)) {//剩余期数都收利息
                logger.info("所有剩余期数抛出利息交易账户");
                castAccountTransactionBeans = planInfoList.stream()
                        .map(CollectorsUtils.tranToUncheck(getIntrAcct))//生成交易账户
                        .filter(Objects::nonNull)//筛选生成交易账户不为空
                        .collect(Collectors.toList());
            } else if (TransBizConstant.ADVANCE_SETTLE_FEE_METHOD_2.equals(intMethod)) {
                int intTenor = res.getIntTenor();
                logger.info("剩余{}期抛出利息交易账户", intTenor);
                castAccountTransactionBeans = planInfoList.stream()
                        .filter(plan -> plan.getBillingTenor() <= intTenor + loanAccountInfo.getCastTenor())//筛选符合期数范围
                        .map(CollectorsUtils.tranToUncheck(getIntrAcct))//生成交易账户
                        .filter(Objects::nonNull)//筛选生成交易账户不为空
                        .collect(Collectors.toList());
            }
        }
        return castAccountTransactionBeans;
    }



    /**
     * 计算提前还款手续费，获取费用交易账户
     * @param loanMain
     * @param loanAcct
     * @param bussinessDate
     * @param liabilityFlag
     * @return
     * @throws TxnException
     */
    @Override
    public void castPrePayFeeAcct(InvestorPaymentSaveBean saveBean,AmLoanMainInvestorInfo loanMain,
                                                               AmLoanAccountInvestorInfo loanAcct, Date bussinessDate, String liabilityFlag) throws TxnException {
        logger.info("计算提前还款费用，获取费用交易账户,loanMainInfo:{}", BeanUtils.toMap(loanMain));

        PrInvestorPrepaymentFee res = prepaymentFeeService.findByPrepaymentFeeId(loanMain.getInvestorPrepayTableId(),loanMain.getTenantId());
        logger.info("计算提前还款费用，获取费用交易账户,res:{}", BeanUtils.toMap(res));
        BigDecimal prePayFee = this.calculationPrePayFee(res,loanAcct);
        if (prePayFee.compareTo(BigDecimal.ZERO) <= 0) {
            logger.info("无费用");
            return;
        }
        InvestorCastAccountTransactionBean castPaymentFeeAccount = accountService.castPaymentFeeAccount(loanMain,loanAcct,
                TransBizConstant.TXN_CODE_INST_PREPAY_FEE, prePayFee, bussinessDate,liabilityFlag);

        saveBean.addSaveAcct(castPaymentFeeAccount.getAmAccountMainInfo());
        saveBean.addAcctGroupByTypeMap(castPaymentFeeAccount.getAmAccountMainInfo());
        saveBean.addSaveGlList(castPaymentFeeAccount.getTlGlInterfaceInfoList());
        logger.info("计算提前还款费用，获取费用交易账户,castPaymentFeeAccount:{}", BeanUtils.toMap(castPaymentFeeAccount));
    }

    /**
     * 计算提前还款罚费
     * @param res
     * @param loanAcct
     * @return
     */
    private BigDecimal calculationPrePayFee(PrInvestorPrepaymentFee res,AmLoanAccountInvestorInfo loanAcct) {
        if(null !=res.getWaiveFeeTenor() && res.getWaiveFeeTenor() <= loanAcct.getPayedTenor()){
            return BigDecimal.ZERO;
        }
        return res.getFeeChargeAmount();
    }
}
